package io.gitee.kotle.android.adapter

import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.gitee.kotle.android.utils.ignoreError
import io.gitee.kotle.android.utils.withIoThread
import io.gitee.kotle.android.utils.withMainThread

open class RecyclerViewAdapter<Data>(
    private val areItemTheSame: ((old: Data?, new: Data?) -> Boolean)? = null/*是否是同一组数据*/,
    private val areContentsTheSame: ((old: Data?, new: Data?) -> Boolean)? = null/*是否内容相同*/
) : RecyclerView.Adapter<RecyclerViewHolder<Data, *>>(),
    IRecyclerViewAdapter<Data> by DefaultRecyclerViewAdapterImpl() {
    private var datas = mutableListOf<Data>()

    /**
     * 当前对象
     */
    val currentList: List<Data>
        get() = datas

    private val _adapterDiffCall by lazy {
        AdapterDiffCall<Data>(areItemTheSame, areContentsTheSame)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder<Data, *> {
        return onCreateRecyclerViewHolder(parent, viewType)
    }

    override fun onBindViewHolder(holder: RecyclerViewHolder<Data, *>, position: Int) {

    }


    override fun onBindViewHolder(
        holder: RecyclerViewHolder<Data, *>,
        position: Int,
        payloads: MutableList<Any>
    ) {
        super.onBindViewHolder(holder, position, payloads)
        onBindRecyclerViewHolder(
            holder,
            position,
            payloads,
            position == itemCount - 1,
            getItem(position)
        )
    }

    override fun getItemCount(): Int {
        return datas.count()
    }

    override fun getItemViewType(position: Int): Int {
        return getRecyclerViewItemViewType(position, getItem(position))
    }

    open fun getItem(position: Int): Data? {
        return ignoreError { datas[position] }
    }

    override fun onViewAttachedToWindow(holder: RecyclerViewHolder<Data, *>) {
        super.onViewAttachedToWindow(holder)
        onRecyclerViewHolderAttachedToWindow(holder)
    }

    override fun onViewDetachedFromWindow(holder: RecyclerViewHolder<Data, *>) {
        super.onViewDetachedFromWindow(holder)
        onRecyclerViewHolderDetachedFromWindow(holder)
    }

    override fun onViewRecycled(holder: RecyclerViewHolder<Data, *>) {
        super.onViewRecycled(holder)
        onRecyclerViewHolderRecycled(holder)
    }

    override fun onFailedToRecycleView(holder: RecyclerViewHolder<Data, *>): Boolean {
        onRecyclerViewHolderFailedToRecycleView(holder)
        return super.onFailedToRecycleView(holder)
    }

    private fun getDiffResult(
        newList: List<Data>?,
        isReplaceDatas: Boolean,
    ): DiffUtil.DiffResult? {
        if (newList == null) {
            val count = itemCount
            datas.clear()
            notifyItemRangeRemoved(0, count)
            return null
        }
        val oldData = datas.toMutableList()
        if (isReplaceDatas && newList is MutableList<Data>) {
            onCurrentListChanged(datas, newList)
            datas = newList
        } else {
            datas.clear()
            datas.addAll(newList)
        }
        _adapterDiffCall.old = oldData
        _adapterDiffCall.new = datas
        return DiffUtil.calculateDiff(_adapterDiffCall, true)
    }

    /**
     * 主线程刷新
     */
    fun submitList(
        newList: List<Data>?,
        isReplaceDatas: Boolean,
    ) {
        getDiffResult(newList, isReplaceDatas)?.dispatchUpdatesTo(this)
    }

    /**
     * 异步刷新
     */
    suspend fun submitListAsync(
        newList: List<Data>?,
        isReplaceDatas: Boolean,
    ) {
        val result = withIoThread {
            getDiffResult(newList, isReplaceDatas)
        } ?: return
        withMainThread {
            result.dispatchUpdatesTo(this@RecyclerViewAdapter)
        }
    }

    open fun onCurrentListChanged(previousList: List<Data>, currentList: List<Data>) {}

    override fun getItemData(position: Int): Data? {
        return getItem(position)
    }

    /**
     * 移除item
     */
    fun removeItem(position: Int, notify: Boolean = true) {
        datas.removeAt(position)
        if (notify) {
            notifyItemRemoved(position)
        }
    }

    /**
     * 移除item
     */
    fun removeItem(startPosition: Int, count: Int, notify: Boolean = true) {
        repeat(count) {
            datas.removeAt(startPosition + (count - it) - 1)
        }
        if (notify) {
            notifyItemRangeRemoved(startPosition, count)
        }
    }

    /**
     * 移除item
     */
    fun removeItem(data: Data, notify: Boolean = true) {
        val index = datas.indexOf(data)
        if (index >= 0) {
            removeItem(index, notify)
        }
    }

    /**
     * 移除item
     */
    fun removeItems(data: List<Data>?, notify: Boolean = true) {
        data?.forEach {
            removeItem(it, notify)
        }
    }

    /**
     * 更新item
     */
    fun updateItem(index: Int, data: Data, payload: Any? = null, notify: Boolean = true) {
        datas[index] = data
        if (notify) {
            notifyItemChanged(index, payload)
        }
    }

    /**
     * 添加item
     */
    fun addItem(data: Data, index: Int? = null, notify: Boolean = true) {
        val insertIndex = index ?: datas.count()
        datas.add(insertIndex, data)
        if (notify) {
            notifyItemInserted(insertIndex)
        }
    }

    /**
     * 添加item
     */
    fun addItems(data: List<Data>?, index: Int? = null, notify: Boolean = true) {
        if (data.isNullOrEmpty()) {
            return
        }
        val insertIndex = index ?: datas.count()
        datas.addAll(insertIndex, data)
        if (notify) {
            notifyItemRangeInserted(insertIndex, data.count())
        }
    }
}